package com.quiz.common.mybatis.handler;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.quiz.common.core.domain.R;
import com.quiz.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;


/**
 * Mybatis异常处理器
 *
 * @author ahuan
 */
@Slf4j
@Order(Integer.MIN_VALUE)
@RestControllerAdvice
public class MybatisExceptionHandler {

    /**
     * 主键或UNIQUE索引，数据重复异常
     */
    @ExceptionHandler(DuplicateKeyException.class)
    public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        printRequestParams(request);
        log.error("请求地址'{}',数据库中已存在记录'{}'", requestUri, e.getMessage());
        return R.fail(10001, "数据库中已存在该记录，请联系管理员确认");
    }

    /**
     * Mybatis系统异常 通用处理
     */
    @ExceptionHandler(MyBatisSystemException.class)
    public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        String message = e.getMessage();
        if (StringUtils.contains("CannotFindDataSourceException", message)) {
            log.error("请求地址'{}', 未找到数据源", requestUri);
            return R.fail("未找到数据源，请联系管理员确认");
        }
        printRequestParams(request);
        log.error("请求地址'{}', Mybatis系统异常", requestUri, e);
        return R.fail(10001, message);
    }

    /**
     * 打印请求参数
     *
     * @param request 请求
     * @author ahuan
     * @date 2024-07-03 15:19:11
     **/
    @SuppressWarnings("all")
    private void printRequestParams(HttpServletRequest request) {
        if (isJsonRequest(request)) {
            // 打印请求参数
            String jsonParam = ServletUtil.getBody(request);
            if (CharSequenceUtil.isNotBlank(jsonParam)) {
                log.error("请求参数 => URL[{}],参数类型[json],参数: {}", request.getMethod() + " " + request.getRequestURI(), jsonParam);
            } else {
                log.error("请求参数 => URL[{}],参数类型[json],无参数", request.getMethod() + " " + request.getRequestURI());
            }
            return;
        }
        // 打印请求参数
        Map<String, String> params = ServletUtil.getParamMap(request);
        if (params.isEmpty()) {
            log.error("请求参数 => URL[{}],无参数", request.getMethod() + " " + request.getRequestURI());
        } else {
            log.error("请求参数 => URL[{}],参数: {}", request.getMethod() + " " + request.getRequestURI(), params);
        }
    }

    /**
     * 判断本次请求的数据类型是否为json
     *
     * @param request request
     * @return boolean
     */
    private boolean isJsonRequest(HttpServletRequest request) {
        String contentType = request.getContentType();
        if (contentType != null) {
            return CharSequenceUtil.startWithIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE);
        }
        return false;
    }
}
